using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using System.Text.Json;

namespace SeataNet.Core.Saga
{
    /// <summary>
    /// Saga状态存储接口
    /// </summary>
    public interface ISagaStateStore
    {
        /// <summary>
        /// 保存事务上下文
        /// </summary>
        /// <param name="context">事务上下文</param>
        /// <returns>任务</returns>
        Task SaveTransactionContextAsync(SagaTransactionContext context);

        /// <summary>
        /// 更新事务上下文
        /// </summary>
        /// <param name="context">事务上下文</param>
        /// <returns>任务</returns>
        Task UpdateTransactionContextAsync(SagaTransactionContext context);

        /// <summary>
        /// 获取事务上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <returns>事务上下文</returns>
        Task<SagaTransactionContext> GetTransactionContextAsync(string xid);

        /// <summary>
        /// 删除事务上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <returns>任务</returns>
        Task DeleteTransactionContextAsync(string xid);

        /// <summary>
        /// 保存步骤上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <param name="context">步骤上下文</param>
        /// <returns>任务</returns>
        Task SaveStepContextAsync(string xid, SagaStepContext context);

        /// <summary>
        /// 更新步骤上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <param name="context">步骤上下文</param>
        /// <returns>任务</returns>
        Task UpdateStepContextAsync(string xid, SagaStepContext context);

        /// <summary>
        /// 获取步骤上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <param name="stepId">步骤ID</param>
        /// <returns>步骤上下文</returns>
        Task<SagaStepContext> GetStepContextAsync(string xid, string stepId);

        /// <summary>
        /// 获取事务的所有步骤上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <returns>步骤上下文列表</returns>
        Task<List<SagaStepContext>> GetStepContextsAsync(string xid);

        /// <summary>
        /// 删除步骤上下文
        /// </summary>
        /// <param name="xid">事务XID</param>
        /// <param name="stepId">步骤ID</param>
        /// <returns>任务</returns>
        Task DeleteStepContextAsync(string xid, string stepId);
    }

    /// <summary>
    /// 内存Saga状态存储实现
    /// </summary>
    public class InMemorySagaStateStore : ISagaStateStore
    {
        private readonly ILogger<InMemorySagaStateStore> _logger;
        private readonly ConcurrentDictionary<string, SagaTransactionContext> _transactionContexts;
        private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, SagaStepContext>> _stepContexts;

        public InMemorySagaStateStore(ILogger<InMemorySagaStateStore> logger)
        {
            _logger = logger;
            _transactionContexts = new ConcurrentDictionary<string, SagaTransactionContext>();
            _stepContexts = new ConcurrentDictionary<string, ConcurrentDictionary<string, SagaStepContext>>();
        }

        public async Task SaveTransactionContextAsync(SagaTransactionContext context)
        {
            await Task.Run(() =>
            {
                _transactionContexts.AddOrUpdate(context.Xid, context, (key, oldValue) => context);
                _logger.LogDebug($"事务上下文已保存: XID={context.Xid}");
            });
        }

        public async Task UpdateTransactionContextAsync(SagaTransactionContext context)
        {
            await Task.Run(() =>
            {
                _transactionContexts.AddOrUpdate(context.Xid, context, (key, oldValue) => context);
                _logger.LogDebug($"事务上下文已更新: XID={context.Xid}");
            });
        }

        public async Task<SagaTransactionContext> GetTransactionContextAsync(string xid)
        {
            return await Task.Run(() =>
            {
                _transactionContexts.TryGetValue(xid, out var context);
                _logger.LogDebug($"获取事务上下文: XID={xid}, Found={context != null}");
                return context;
            });
        }

        public async Task DeleteTransactionContextAsync(string xid)
        {
            await Task.Run(() =>
            {
                _transactionContexts.TryRemove(xid, out _);
                _stepContexts.TryRemove(xid, out _);
                _logger.LogDebug($"事务上下文已删除: XID={xid}");
            });
        }

        public async Task SaveStepContextAsync(string xid, SagaStepContext context)
        {
            await Task.Run(() =>
            {
                var steps = _stepContexts.GetOrAdd(xid, _ => new ConcurrentDictionary<string, SagaStepContext>());
                steps.AddOrUpdate(context.StepId, context, (key, oldValue) => context);
                _logger.LogDebug($"步骤上下文已保存: XID={xid}, StepId={context.StepId}");
            });
        }

        public async Task UpdateStepContextAsync(string xid, SagaStepContext context)
        {
            await Task.Run(() =>
            {
                var steps = _stepContexts.GetOrAdd(xid, _ => new ConcurrentDictionary<string, SagaStepContext>());
                steps.AddOrUpdate(context.StepId, context, (key, oldValue) => context);
                _logger.LogDebug($"步骤上下文已更新: XID={xid}, StepId={context.StepId}");
            });
        }

        public async Task<SagaStepContext> GetStepContextAsync(string xid, string stepId)
        {
            return await Task.Run(() =>
            {
                if (_stepContexts.TryGetValue(xid, out var steps))
                {
                    steps.TryGetValue(stepId, out var context);
                    _logger.LogDebug($"获取步骤上下文: XID={xid}, StepId={stepId}, Found={context != null}");
                    return context;
                }
                return null;
            });
        }

        public async Task<List<SagaStepContext>> GetStepContextsAsync(string xid)
        {
            return await Task.Run(() =>
            {
                if (_stepContexts.TryGetValue(xid, out var steps))
                {
                    var result = steps.Values.ToList();
                    _logger.LogDebug($"获取事务的所有步骤上下文: XID={xid}, Count={result.Count}");
                    return result;
                }
                return new List<SagaStepContext>();
            });
        }

        public async Task DeleteStepContextAsync(string xid, string stepId)
        {
            await Task.Run(() =>
            {
                if (_stepContexts.TryGetValue(xid, out var steps))
                {
                    steps.TryRemove(stepId, out _);
                    _logger.LogDebug($"步骤上下文已删除: XID={xid}, StepId={stepId}");
                }
            });
        }
    }

    /// <summary>
    /// 文件Saga状态存储实现
    /// </summary>
    public class FileSagaStateStore : ISagaStateStore
    {
        private readonly ILogger<FileSagaStateStore> _logger;
        private readonly string _storagePath;
        private readonly SemaphoreSlim _semaphore;

        public FileSagaStateStore(ILogger<FileSagaStateStore> logger, string storagePath = "./saga-state")
        {
            _logger = logger;
            _storagePath = storagePath;
            _semaphore = new SemaphoreSlim(1, 1);
            
            // 确保存储目录存在
            if (!Directory.Exists(_storagePath))
            {
                Directory.CreateDirectory(_storagePath);
            }
        }

        public async Task SaveTransactionContextAsync(SagaTransactionContext context)
        {
            await _semaphore.WaitAsync();
            try
            {
                var filePath = GetTransactionContextFilePath(context.Xid);
                var json = JsonSerializer.Serialize(context, new JsonSerializerOptions { WriteIndented = true });
                await File.WriteAllTextAsync(filePath, json);
                _logger.LogDebug($"事务上下文已保存到文件: XID={context.Xid}, FilePath={filePath}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"保存事务上下文到文件失败: XID={context.Xid}");
                throw;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public async Task UpdateTransactionContextAsync(SagaTransactionContext context)
        {
            await SaveTransactionContextAsync(context);
        }

        public async Task<SagaTransactionContext> GetTransactionContextAsync(string xid)
        {
            await _semaphore.WaitAsync();
            try
            {
                var filePath = GetTransactionContextFilePath(xid);
                if (!File.Exists(filePath))
                {
                    _logger.LogDebug($"事务上下文文件不存在: XID={xid}, FilePath={filePath}");
                    return null;
                }

                var json = await File.ReadAllTextAsync(filePath);
                var context = JsonSerializer.Deserialize<SagaTransactionContext>(json);
                _logger.LogDebug($"从事务上下文文件加载: XID={xid}, FilePath={filePath}");
                return context;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"从事务上下文文件加载失败: XID={xid}");
                return null;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public async Task DeleteTransactionContextAsync(string xid)
        {
            await _semaphore.WaitAsync();
            try
            {
                var filePath = GetTransactionContextFilePath(xid);
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                    _logger.LogDebug($"事务上下文文件已删除: XID={xid}, FilePath={filePath}");
                }

                // 删除事务目录下的所有步骤文件
                var stepDirectory = GetStepDirectoryPath(xid);
                if (Directory.Exists(stepDirectory))
                {
                    Directory.Delete(stepDirectory, true);
                    _logger.LogDebug($"步骤目录已删除: XID={xid}, DirectoryPath={stepDirectory}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"删除事务上下文文件失败: XID={xid}");
                throw;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public async Task SaveStepContextAsync(string xid, SagaStepContext context)
        {
            await _semaphore.WaitAsync();
            try
            {
                var stepDirectory = GetStepDirectoryPath(xid);
                if (!Directory.Exists(stepDirectory))
                {
                    Directory.CreateDirectory(stepDirectory);
                }

                var filePath = GetStepContextFilePath(xid, context.StepId);
                var json = JsonSerializer.Serialize(context, new JsonSerializerOptions { WriteIndented = true });
                await File.WriteAllTextAsync(filePath, json);
                _logger.LogDebug($"步骤上下文已保存到文件: XID={xid}, StepId={context.StepId}, FilePath={filePath}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"保存步骤上下文到文件失败: XID={xid}, StepId={context.StepId}");
                throw;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public async Task UpdateStepContextAsync(string xid, SagaStepContext context)
        {
            await SaveStepContextAsync(xid, context);
        }

        public async Task<SagaStepContext> GetStepContextAsync(string xid, string stepId)
        {
            await _semaphore.WaitAsync();
            try
            {
                var filePath = GetStepContextFilePath(xid, stepId);
                if (!File.Exists(filePath))
                {
                    _logger.LogDebug($"步骤上下文文件不存在: XID={xid}, StepId={stepId}, FilePath={filePath}");
                    return null;
                }

                var json = await File.ReadAllTextAsync(filePath);
                var context = JsonSerializer.Deserialize<SagaStepContext>(json);
                _logger.LogDebug($"从步骤上下文文件加载: XID={xid}, StepId={stepId}, FilePath={filePath}");
                return context;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"从步骤上下文文件加载失败: XID={xid}, StepId={stepId}");
                return null;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public async Task<List<SagaStepContext>> GetStepContextsAsync(string xid)
        {
            await _semaphore.WaitAsync();
            try
            {
                var stepDirectory = GetStepDirectoryPath(xid);
                if (!Directory.Exists(stepDirectory))
                {
                    _logger.LogDebug($"步骤目录不存在: XID={xid}, DirectoryPath={stepDirectory}");
                    return new List<SagaStepContext>();
                }

                var result = new List<SagaStepContext>();
                var files = Directory.GetFiles(stepDirectory, "*.json");
                
                foreach (var file in files)
                {
                    try
                    {
                        var json = await File.ReadAllTextAsync(file);
                        var context = JsonSerializer.Deserialize<SagaStepContext>(json);
                        if (context != null)
                        {
                            result.Add(context);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"加载步骤上下文文件失败: FilePath={file}");
                    }
                }

                _logger.LogDebug($"加载事务的所有步骤上下文: XID={xid}, Count={result.Count}");
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"加载事务的所有步骤上下文失败: XID={xid}");
                return new List<SagaStepContext>();
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public async Task DeleteStepContextAsync(string xid, string stepId)
        {
            await _semaphore.WaitAsync();
            try
            {
                var filePath = GetStepContextFilePath(xid, stepId);
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                    _logger.LogDebug($"步骤上下文文件已删除: XID={xid}, StepId={stepId}, FilePath={filePath}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"删除步骤上下文文件失败: XID={xid}, StepId={stepId}");
                throw;
            }
            finally
            {
                _semaphore.Release();
            }
        }

        private string GetTransactionContextFilePath(string xid)
        {
            return Path.Combine(_storagePath, $"{xid}.json");
        }

        private string GetStepDirectoryPath(string xid)
        {
            return Path.Combine(_storagePath, xid);
        }

        private string GetStepContextFilePath(string xid, string stepId)
        {
            return Path.Combine(GetStepDirectoryPath(xid), $"{stepId}.json");
        }
    }
}